`include "defines.svh"
`include "CP0Defines.svh"
`include "CacheDefines.svh"
module mycpu_top(
        ext_int,
         
         aclk,   
         aresetn,
         
         arid,   
         araddr, 
         arlen,  
         arsize, 
         arburst,
         arlock, 
         arcache,
         arprot, 
         arvalid,
         arready,
                
         rid,    
         rdata,  
         rresp,  
         rlast,  
         rvalid, 
         rready, 
                
         awid,   
         awaddr, 
         awlen,  
         awsize, 
         awburst,
         awlock, 
         awcache,
         awprot, 
         awvalid,
         awready,
             
         wid,    
         wdata,  
         wstrb,  
         wlast,  
         wvalid, 
         wready, 
             
         bid,    
         bresp,  
         bvalid, 
         bready,

         debug_wb_pc,
         debug_wb_rf_wen,
         debug_wb_rf_wnum,
         debug_wb_rf_wdata
);

    input  logic  [ 5:0] ext_int;
    input  logic         aclk;
    input  logic         aresetn;
    output logic  [ 3:0] arid;
    output logic  [31:0] araddr;
    output logic  [ 3:0] arlen;
    output logic  [ 2:0] arsize;
    output logic  [ 1:0] arburst;
    output logic  [ 1:0] arlock;
    output logic  [ 3:0] arcache;
    output logic  [ 2:0] arprot;
    output logic         arvalid;
    input  logic         arready;
    input  logic  [ 3:0] rid;
    input  logic  [31:0] rdata;
    input  logic  [ 1:0] rresp;
    input  logic         rlast;
    input  logic         rvalid;
    output logic         rready;
    output logic  [ 3:0] awid;
    output logic  [31:0] awaddr;
    output logic  [ 3:0] awlen;
    output logic  [ 2:0] awsize;
    output logic  [ 1:0] awburst;
    output logic  [ 1:0] awlock;
    output logic  [ 3:0] awcache;
    output logic  [ 2:0] awprot;
    output logic         awvalid;
    input  logic         awready;
    output logic  [ 3:0] wid;
    output logic  [31:0] wdata;
    output logic  [ 3:0] wstrb;
    output logic         wlast;
    output logic         wvalid;
    input  logic         wready;
    input  logic  [ 3:0] bid;
    input  logic  [ 1:0] bresp;
    input  logic         bvalid;
    output logic         bready;

   output [31:0]        debug_wb_pc;        
   output [31:0]        debug_wb_rf_wdata;  
   output [3:0]         debug_wb_rf_wen;    
   output [4:0]         debug_wb_rf_wnum;   

logic [1:0] IsExceptionorEret;  //总的代表MEM级是否有异常或例外的信号，0代表没有异常和例外，1代表有异常，2代表有例外

logic [31:0] CP0EPC_out;
//PREIF
logic [31:0]PREIF_PC;
logic [31:0]PREIF_PhyPC;
logic [31:0]PREIF_NPC;
logic PREIF_PCWr; 
ExceptionType PREIF_ExceptionType;
//
//PREIF_IF
logic PREIF_IF_Stall;
logic PREIF_IF_Flush;
logic PREIF_IF_Flush_Exception;
//IF
logic [31:0]IF_PC;
logic [31:0]IF_NPC;
logic [31:0]IF_Instr;
ExceptionType IF_ExceptionType;
//IF_ID
logic IF_ID_Flush; 
logic IF_ID_Stall;
logic IF_ID_Flush_Exception;
//
logic EXE_MEM_Flush_Exception;
//ID
logic [31:0]ID_PC;
logic [31:0]ID_NPC;
logic [31:0]ID_Instr;
logic ID_EXE_Flush_Exception;
ExceptionType ID_ExceptionType;
logic [1:0]ID_EXTOp;
logic [4:0]ID_ALUOp;
logic ID_DMWr;
logic ID_ALU_DataA_Sig;
logic ID_ALU_DataB_Sig;
logic [2:0]ID_Reg_Writed;
logic [2:0]ID_DMOp;
logic ID_MemToRegWr;
logic ID_Immjump;
logic ID_IsBranch;
logic [1:0]ID_Data_To_Reg_Sel;
logic [31:0]ID_Imm_32;
logic [31:0]ID_Rs_Data;
logic [31:0]ID_Rt_Data;
logic [31:0]ID_Rs_Data_End;
logic [31:0]ID_Rt_Data_End;
logic [4:0]ID_RW;                      
logic [4:0]ID_Rs;
logic [4:0]ID_Rt;
ExceptionType ID_ExceptionTypeEnd;
logic ID_CP0Wr;
logic ID_DMRd;
//
assign ID_Rs=ID_Instr[25:21];
assign ID_Rt=ID_Instr[20:16];
//

//ID_EXE
logic ID_EXE_Flush_DH;
logic ID_EXE_Flush;
logic ID_EXE_Stall;
//EXE
logic EXE_ALU2_Stall;
logic EXE_Finish;
logic [31:0]EXE_DatatoHI;
logic [31:0]EXE_DatatoLO;
logic [31:0]ALU_A;
logic [31:0]ALU_B;
logic [31:0]ALU_Out;
logic [31:0]ALU_Out_End;
logic [31:0]HI_Data;
logic [31:0]LO_Data;
logic EXE_CP0Wr;
logic EXE_DMRd;
logic EXE_IsBranch;
logic EXE_Immjump;
logic [31:0]EXE_PC;
logic [31:0]EXE_Instr;
logic [31:0]EXE_NPC;
logic [4:0]EXE_ALUOp;
logic EXE_DMWr;
logic EXE_ALU_DataA_Sig;
logic EXE_ALU_DataB_Sig;
logic [2:0]EXE_Reg_Writed;
logic [2:0]EXE_Reg_Writed_End;//need to pass
logic [2:0]EXE_Reg_Writed_Exception;
logic [2:0]EXE_DMOp;
logic EXE_MemToRegWr;
logic [1:0]EXE_Data_To_Reg_Sel;
logic [31:0]EXE_Rs_Data;
logic [31:0]EXE_Rt_Data;
logic [31:0]EXE_Imm_32;
logic [4:0]EXE_RW;
logic [31:0] EXE_Rs_Data_End;
logic [31:0] EXE_Rt_Data_End;
logic [4:0] EXE_Rs;
logic [4:0] EXE_Rt;

ExceptionType EXE_ExceptionType;
ExceptionType EXE_ExceptionTypeEnd;
//
logic DH_IF_PCWr;
logic DH_IF_IDWr;
logic mfc0_DH;
//

//EXE_MEM
logic EXE_MEM_Flush;
logic EXE_MEM_Stall;
//MEM
logic MEM_CP0Wr;
logic MEM_DMRd;
logic [31:0]MEM_PC;
logic [31:0]MEM_NPC;
logic [31:0]MEM_Instr;
logic [2:0]MEM_DMOp;
logic [31:0]MEM_Data_Writed;//MEM_Rt_Data
logic [2:0]MEM_Reg_Writed;
logic [2:0]MEM_Reg_Writed_End;    
logic [31:0]MEM_ALU_Out;//MEM_ALU_Out 
logic [31:0]MEM_DPhysicalAddr;   
logic MEM_DMWr;
logic MEM_DMWr_End;
logic [4:0]MEM_RW;
logic [4:0]MEM_RW_End;          
logic MEM_MemToRegWr;
logic MEM_MemToRegWr_End;
logic [1:0]MEM_Data_To_Reg_Sel;
logic MEM_IsBranch;
logic MEM_Immjump;
logic MEM_isDelaySlot;
ExceptionType MEM_ExceptionType;
ExceptionType MEM_ExceptionTypeNew;
ExceptionType MEM_ExceptionTypeEnd;
//
//MEM_MEM2
logic MEM_MEM2_Flush;
logic MEM_MEM2_Stall;
//
//MEM2
logic MEM2_CP0Wr;
logic MEM2_DMRd;
logic [31:0]MEM2_PC;
logic [31:0]MEM2_NPC;
logic [31:0]MEM2_Instr;
logic [2:0]MEM2_DMOp;
logic [31:0]MEM2_Data_Writed;//MEM2_Rt_Data
logic [2:0]MEM2_Reg_Writed;  
logic MEM2_DMWr;
logic [31:0]MEM2_ALU_Out;
logic [4:0]MEM2_RW;
logic [4:0]MEM2_RW_End;          
logic MEM2_MemToRegWr;
logic [31:0]Data_From_DM;
logic [31:0]Data_From_DM_AfterExt;
logic [1:0]MEM2_Data_To_Reg_Sel;
logic MEM2_IsBranch;
logic MEM2_Immjump;
logic MEM2_isDelaySlot;
ExceptionType MEM2_ExceptionType;
//MEM2_WB
logic MEM2_WB_Flush;
logic MEM2_WB_Stall;
//WB
logic WB_CP0Wr;
logic WB_DMRd;
logic [31:0]WB_PC;
logic [31:0]WB_NPC;
logic [31:0]WB_Instr;
logic [4:0]WB_RW;
logic [4:0]WB_RW_End;
logic [2:0]WB_Reg_Writed;
logic [1:0]WB_Data_To_Reg_Sel;
logic [31:0]WB_ALU_Out;// == MEM_ALU_Out
logic [31:0]WB_Data_From_DM;
logic WB_RFWr;
logic [31:0] WB_CP0RdData;

ExceptionType WB_ExceptionType;

logic [31:0]Data_To_Reg;
logic [31:0] MEM2_CP0RdData;
logic [31:0] CP0BadVAddr;
logic [31:0] CP0Status;
logic [31:0] CP0Cause;
logic [31:0] CP0EPC;
logic [31:0] CP0Count;
logic [31:0] CP0Compare;
logic Cp0TimerInterrupt;
logic [4:0] CP0RdAddr;
logic [4:0] CP0WrAddr;
logic MEM_CP0Wr_EXc;
//
logic HiLo_Not_Flush;

logic Is_Interrupt;
//
FactResult EXE_FactResult;
PredictResult IF_PredictResult;
PredictResult ID_PredictResult;
PredictResult EXE_PredictResult;
logic EXE_Prediction_Failed;
logic EXE_IsTaken;
logic EXE_PF_FlushAll;
logic [31:0] EXE_Correction_Vector;
//

PREIF_IF U_PREIF_IF(
    .clk(aclk),
    .reset(aresetn),
    .PREIF_IF_Stall(PREIF_IF_Stall),
    .PREIF_IF_Flush(PREIF_IF_Flush),

    .PREIF_PC(PREIF_PC),
    .PREIF_NPC(PREIF_NPC),
    .PREIF_ExceptionType(PREIF_ExceptionType),

    .IF_PC(IF_PC),
    .IF_NPC(IF_NPC),
    .IF_ExceptionType(IF_ExceptionType)
);

IF_ID U_IF_ID(
    .clk(aclk),
    .reset(aresetn),
    .IF_ID_Flush(IF_ID_Flush),
    .IF_ID_Stall(IF_ID_Stall),
    .IF_PC(IF_PC),
    .IF_NPC(IF_NPC),
    .IF_Instr(IF_Instr),
    .IF_ExceptionType(IF_ExceptionType),
    .IF_PredictResult(IF_PredictResult),
    // output
    .ID_PC(ID_PC),
    .ID_NPC(ID_NPC),
    .ID_Instr(ID_Instr),
    .ID_ExceptionType(ID_ExceptionType),
    .ID_PredictResult(ID_PredictResult)
);
assign MEM_RW_End=(MEM_ExceptionTypeEnd==`NoException)?MEM_RW:5'b00000;
assign MEM2_RW_End=(MEM2_ExceptionType==`NoException)?MEM2_RW:5'b00000;
EXE_MEM U_EXE_MEM(
    .clk(aclk),
    .reset(aresetn),
    .EXE_MEM_Flush(EXE_MEM_Flush),
    .EXE_MEM_Stall(EXE_MEM_Stall),

    .EXE_PC(EXE_PC),
    .EXE_NPC(EXE_NPC),
    .EXE_Instr(EXE_Instr),
    .EXE_DMOp(EXE_DMOp),
    .EXE_Rt_Data(EXE_Rt_Data_End),
    .EXE_DMWr(EXE_DMWr),
    .ALU_Out_End(ALU_Out_End),
    .EXE_RW(EXE_RW),
    .EXE_MemToRegWr(EXE_MemToRegWr),
    .EXE_Data_To_Reg_Sel(EXE_Data_To_Reg_Sel),
    .EXE_IsBranch(EXE_IsBranch),
    .EXE_Immjump(EXE_Immjump),
    .EXE_CP0Wr(EXE_CP0Wr),
    .EXE_DMRd(EXE_DMRd),
    .EXE_ExceptionTypeEnd(EXE_ExceptionTypeEnd),
    .EXE_Reg_Writed_End(EXE_Reg_Writed_End),

    .MEM_PC(MEM_PC),
    .MEM_NPC(MEM_NPC),
    .MEM_Instr(MEM_Instr),
    .MEM_DMOp(MEM_DMOp),
    .MEM_Data_Writed(MEM_Data_Writed),
    .MEM_DMWr(MEM_DMWr),
    .MEM_ALU_Out(MEM_ALU_Out),
    .MEM_RW(MEM_RW),
    .MEM_MemToRegWr(MEM_MemToRegWr),
    .MEM_Data_To_Reg_Sel(MEM_Data_To_Reg_Sel),
    .MEM_IsBranch(MEM_IsBranch),
    .MEM_Immjump(MEM_Immjump),
    .MEM_CP0Wr(MEM_CP0Wr),
    .MEM_DMRd(MEM_DMRd),
    .MEM_ExceptionType(MEM_ExceptionType),
    .MEM_Reg_Writed(MEM_Reg_Writed)
);


assign MEM_Reg_Writed_End =(MEM_ExceptionTypeEnd == `NoException)?MEM_Reg_Writed:3'b000;
MEM_MEM2 U_MEM_MEM2(
    .clk(aclk),
    .reset(aresetn),

    .MEM_MEM2_Flush(MEM_MEM2_Flush),
    .MEM_MEM2_Stall(MEM_MEM2_Stall),

    .MEM_CP0Wr(MEM_CP0Wr),
    .MEM_DMRd(MEM_DMRd),
    .MEM_PC(MEM_PC),
    .MEM_NPC(MEM_NPC),
    .MEM_Instr(MEM_Instr),
    .MEM_DMOp(MEM_DMOp),
    .MEM_Data_Writed(MEM_Data_Writed),
    .MEM_Reg_Writed_End(MEM_Reg_Writed_End),        
    .MEM_DMWr(MEM_DMWr_End),
    .MEM_ALU_Out(MEM_ALU_Out),
    .MEM_RW_End(MEM_RW_End),          
    .MEM_MemToRegWr(MEM_MemToRegWr),
    .MEM_Data_To_Reg_Sel(MEM_Data_To_Reg_Sel),
    .MEM_IsBranch(MEM_IsBranch),
    .MEM_Immjump(MEM_Immjump),
    .MEM_isDelaySlot(MEM_isDelaySlot),
    .MEM_ExceptionTypeEnd(MEM_ExceptionTypeEnd),


    .MEM2_CP0Wr(MEM2_CP0Wr),
    .MEM2_DMRd(MEM2_DMRd),
    .MEM2_PC(MEM2_PC),
    .MEM2_NPC(MEM2_NPC),
    .MEM2_Instr(MEM2_Instr),
    .MEM2_DMOp(MEM2_DMOp),
    .MEM2_Data_Writed(MEM2_Data_Writed),
    .MEM2_Reg_Writed(MEM2_Reg_Writed),   
    .MEM2_DMWr(MEM2_DMWr),
    .MEM2_ALU_Out(MEM2_ALU_Out),
    .MEM2_RW(MEM2_RW),        
    .MEM2_MemToRegWr(MEM2_MemToRegWr),
    .MEM2_Data_To_Reg_Sel(MEM2_Data_To_Reg_Sel),
    .MEM2_IsBranch(MEM2_IsBranch),
    .MEM2_Immjump(MEM2_Immjump),
    .MEM2_isDelaySlot(MEM2_isDelaySlot),
    .MEM2_ExceptionType(MEM2_ExceptionType)
);
MEM2_WB U_MEM2_WB(
    .clk(aclk),
    .reset(aresetn),

    .MEM2_WB_Flush(MEM2_WB_Flush),
    .MEM2_WB_Stall(MEM2_WB_Stall),
    .MEM2_PC(MEM2_PC),
    .MEM2_NPC(MEM2_NPC),
    .MEM2_Instr(MEM2_Instr),
    .MEM2_RW(MEM2_RW_End),
    .MEM2_Data_To_Reg_Sel(MEM2_Data_To_Reg_Sel),
    .MEM2_ALU_Out(MEM2_ALU_Out),
    .Data_From_DM_AfterExt(Data_From_DM_AfterExt),
    .MEM2_IsBranch(MEM2_IsBranch),
    .MEM2_Immjump(MEM2_Immjump),
    .MEM2_CP0Wr(MEM2_CP0Wr),
    .MEM2_DMRd(MEM2_DMRd),
    .MEM2_ExceptionType(MEM2_ExceptionType),
    .MEM2_Reg_Writed(MEM2_Reg_Writed),
    .MEM2_CP0RdData(MEM2_CP0RdData),

    .WB_PC(WB_PC),
    .WB_NPC(WB_NPC),
    .WB_Instr(WB_Instr),
    .WB_RW(WB_RW),
    .WB_Data_To_Reg_Sel(WB_Data_To_Reg_Sel),
    .WB_ALU_Out(WB_ALU_Out),
    .WB_Data_From_DM(WB_Data_From_DM),
    .WB_CP0Wr(WB_CP0Wr),
    .WB_DMRd(WB_DMRd),
    .WB_ExceptionType(WB_ExceptionType),
    .WB_Reg_Writed(WB_Reg_Writed),
    .WB_CP0RdData(WB_CP0RdData)
);
//WB
assign WB_RW_End=(WB_ExceptionType==`NoException)?WB_RW:5'b00000;                                               
assign IF_Instr=(IF_PC==32'b0)?32'b0:cpu_ibus.rdata;
assign Data_From_DM=(MEM2_PC==32'b0)?32'b0:cpu_dbus.rdata; 
assign WB_RFWr=
                    (
                        WB_Reg_Writed == 3'b001||
                        WB_Reg_Writed == 3'b010||
                        WB_Reg_Writed == 3'b011
                    )&&(WB_RW_End!=5'b00000);
logic WB_RFWr_End;
logic RF_CantWr;

assign WB_RFWr_End = (RF_CantWr)?1'b0:WB_RFWr;

assign debug_wb_pc=WB_PC;
assign debug_wb_rf_wen=(WB_RFWr_End)?4'b1111:4'b0000;
assign debug_wb_rf_wnum=WB_RW_End;
assign debug_wb_rf_wdata=Data_To_Reg;


PC PC(
    .clk(aclk),
    .reset(aresetn),
    .NPC(PREIF_NPC),
    .PCWr(PREIF_PCWr),
    // output
    .PCOut(PREIF_PC),
    .PREIF_ExceptionType(PREIF_ExceptionType)
);

MMU U_IMMU(
    .VirtualAddr(PREIF_PC),
    .PhysicalAddr(PREIF_PhyPC),
    .isCache(cpu_ibus.isCache)
);
BranchPredict U_BranchPredict(
    .clk(aclk),
    .rst(aresetn),
    .PREIF_IF_Flush(PREIF_IF_Flush),
    .PREIF_IF_Stall(PREIF_IF_Stall),
    .PREIF_PC(PREIF_PC),
    .EXE_FactResult(EXE_FactResult),
//output
    .IF_PredictResult(IF_PredictResult)
);
BranchSolve U_BranchSolve(
    aclk,
    aresetn,
    EXE_PC,
    PREIF_PC,
    EXE_Instr,
    EXE_IsBranch,
    EXE_Immjump,
    EXE_Imm_32,
    EXE_Rs_Data_End,
    EXE_Rt_Data_End,
    ID_EXE_Stall,
    EXE_PredictResult,
//output
    EXE_FactResult,
    EXE_IsTaken,
    EXE_PF_FlushAll,
    EXE_Prediction_Failed,
    EXE_Correction_Vector
);
NPC U_NPC(
    PREIF_PC,
    IsExceptionorEret,
    CP0EPC_out,
    32'hBFC00380,
    IF_PredictResult,
    EXE_Correction_Vector,
    EXE_PF_FlushAll,
    EXE_Prediction_Failed,
    //output
    PREIF_NPC
);
control U_control(
    ID_Instr,
    ID_ExceptionType,
    // output
    ID_EXTOp,
    ID_ALUOp,
    ID_DMWr,
    ID_ALU_DataA_Sig,
    ID_ALU_DataB_Sig,
    ID_Reg_Writed,
    ID_DMOp,
    ID_MemToRegWr,
    ID_Immjump,
    ID_IsBranch,
    ID_Data_To_Reg_Sel,
    ID_ExceptionTypeEnd,
    ID_CP0Wr,
    ID_DMRd
);
EXT U_EXT(
    ID_Instr[15:0],
    ID_EXTOp,
    ID_Imm_32
);
EXT2 U_EXT2(
    Data_From_DM,
    MEM2_ALU_Out,
    MEM2_Instr,
    Data_From_DM_AfterExt
);

assign EXE_Reg_Writed_End=(EXE_Reg_Writed_Exception==`RegWrited_Non)?EXE_Reg_Writed_Exception:EXE_Reg_Writed;

ID_EXE U_ID_EXE(
    aclk,
    aresetn,
    ID_EXE_Flush,
    ID_EXE_Stall,
    ID_PC, ID_NPC,
    ID_Instr, 
    ID_ALUOp, 
    ID_DMWr, 
    ID_ALU_DataA_Sig, 
    ID_ALU_DataB_Sig, 
    ID_Reg_Writed, 
    ID_DMOp, 
    ID_MemToRegWr, 
    ID_Data_To_Reg_Sel, 
    ID_Imm_32, 
    ID_Rs_Data_End, 
    ID_Rt_Data_End,
    ID_RW, 
    ID_IsBranch, 
    ID_Immjump, 
    ID_CP0Wr, 
    ID_DMRd, 
    ID_Rs,
    ID_Rt, 
    ID_ExceptionTypeEnd,
    ID_PredictResult,

    EXE_PC,
    EXE_NPC, 
    EXE_Instr,  
    EXE_ALUOp,
    EXE_DMWr, 
    EXE_ALU_DataA_Sig, 
    EXE_ALU_DataB_Sig, 
    EXE_Reg_Writed, 
    EXE_DMOp, 
    EXE_MemToRegWr, 
    EXE_Data_To_Reg_Sel, 
    EXE_Imm_32,  
    EXE_Rs_Data, 
    EXE_Rt_Data, 
    EXE_RW, 
    EXE_IsBranch, 
    EXE_Immjump, 
    EXE_CP0Wr, 
    EXE_DMRd,
    EXE_Rs,
    EXE_Rt,
    EXE_ExceptionType,
    EXE_PredictResult
);
assign ALU_A=(EXE_ALU_DataA_Sig)?EXE_Rs_Data_End:{27'b0,EXE_Instr[10:6]};
assign ALU_B=(EXE_ALU_DataB_Sig)?EXE_Rt_Data_End:EXE_Imm_32;

ALU U_ALU(
    ALU_A,
    ALU_B,
    EXE_ALUOp,
    EXE_ExceptionType,
    ALU_Out,
    EXE_ExceptionTypeEnd
);
ALU2 U_ALU2(
    aclk,
    aresetn,
    EXE_ALUOp,
    EXE_Rs_Data_End,
    EXE_Rt_Data_End,
    WB_ExceptionType,
    EXE_DatatoLO,
    EXE_DatatoHI,
    EXE_Finish,
    EXE_ALU2_Stall
);
HILO U_HILO(
    .clk(aclk),
    .reset(aresetn),
    .EXE_Finish(EXE_Finish),
    .HiLo_Not_Flush(HiLo_Not_Flush),
    .EXE_DatatoHI(EXE_DatatoHI),
    .EXE_DatatoLO(EXE_DatatoLO),
    .Data_In(EXE_Rs_Data_End),
    .EXE_Reg_Writed(EXE_Reg_Writed_End),
    .HI_Data(HI_Data),
    .LO_Data(LO_Data)
);

logic Side_DH;
DataHazard U_DataHazard(
    .ID_Instr(ID_Instr),
    .ID_Reg_Writed(ID_Reg_Writed),
    .EXE_Instr(EXE_Instr),
    .EXE_MemToRegWr(EXE_MemToRegWr),
    .EXE_RW(EXE_RW),
    .MEM_Instr(MEM_Instr),
    .EXE_Rt(EXE_Rt),
    .EXE_Rs(EXE_Rs),
    .MEM_RW(MEM_RW),
    .MEM_MemToRegWr(MEM_MemToRegWr),

    .ID_RW(ID_RW),
    .DH_IF_PCWr(DH_IF_PCWr),
    .DH_IF_IDWr(DH_IF_IDWr),
    .ID_EXE_Flush_DH(ID_EXE_Flush_DH),
    .mfc0_DH(mfc0_DH),
    .Side_DH(Side_DH)
);

ALUOutSel U_ALUOutSel(
    ALU_Out,
    HI_Data,
    LO_Data,
    EXE_Instr,
    ALU_Out_End
);


ForwardUnit U_ForwardUnit(
    .MEM_CP0Wr(MEM_CP0Wr),
    .ID_Rs(ID_Instr[25:21]),
    .ID_Rt(ID_Instr[20:16]),
    .ID_Rs_Data(ID_Rs_Data),
    .ID_Rt_Data(ID_Rt_Data),
    .ALU_Out_End(ALU_Out_End),
    .Data_From_DM_AfterExt(Data_From_DM_AfterExt),
    .MEM_ALU_Out(MEM_ALU_Out),
    .MEM2_ALU_Out(MEM2_ALU_Out),
    .EXE_RW(EXE_RW),
    .MEM_RW(MEM_RW_End),
    .MEM2_RW(MEM2_RW_End),
    .EXE_MemToRegWr(EXE_MemToRegWr),
    .MEM_MemToRegWr(MEM_MemToRegWr_End),
    .MEM2_MemToRegWr(MEM2_MemToRegWr),
    .MEM2_CP0RdData(MEM2_CP0RdData),

    .EXE_Instr(EXE_Instr),
    .EXE_PC(EXE_PC),
    .MEM_Instr(MEM_Instr),
    .MEM_PC(MEM_PC),
    .MEM2_Instr(MEM2_Instr),
    .MEM2_PC(MEM2_PC),

    .EXE_Rs(EXE_Rs),
    .EXE_Rt(EXE_Rt),

    .WB_RW(WB_RW_End),
    .WB_CP0RdData(WB_CP0RdData),
    .WB_Data_To_Reg_Sel(WB_Data_To_Reg_Sel),
    .MEM2_Data_To_Reg_Sel(MEM2_Data_To_Reg_Sel),
    .EXE_Rs_Data(EXE_Rs_Data),
    .EXE_Rt_Data(EXE_Rt_Data),
    .EXE_Rs_Data_End(EXE_Rs_Data_End),
    .EXE_Rt_Data_End(EXE_Rt_Data_End),

    .ID_Rs_Data_End(ID_Rs_Data_End),
    .ID_Rt_Data_End(ID_Rt_Data_End)
);

WrControl U_WrControl(
    .PREIF_IF_Flush_Exception(PREIF_IF_Flush_Exception),
    .IF_ID_Flush_Exception(IF_ID_Flush_Exception),
    .ID_EXE_Flush_Exception(ID_EXE_Flush_Exception),
    .EXE_MEM_Flush_Exception(EXE_MEM_Flush_Exception),

    .DH_IF_PCWr(DH_IF_PCWr),
    .DH_IF_IDWr(DH_IF_IDWr),
    .ID_EXE_Flush_DH(ID_EXE_Flush_DH),
    .mfc0_DH(mfc0_DH),
    .Side_DH(Side_DH),

    .EXE_Prediction_Failed(EXE_Prediction_Failed),
    .EXE_IsTaken(EXE_IsTaken),
    .EXE_PF_FlushAll(EXE_PF_FlushAll),

    .EXE_ALU2_Stall(EXE_ALU2_Stall),
    .IsExceptionorEret(IsExceptionorEret),

    .cpu_ibus_busy(cpu_ibus.busy),
    .cpu_dbus_busy(cpu_dbus.busy),

    .PREIF_PCWr(PREIF_PCWr),
    .RF_CantWr(RF_CantWr),
    .PREIF_IF_Stall(PREIF_IF_Stall),
    .IF_ID_Stall(IF_ID_Stall),
    .ID_EXE_Stall(ID_EXE_Stall),
    .EXE_MEM_Stall(EXE_MEM_Stall),
    .MEM_MEM2_Stall(MEM_MEM2_Stall),
    .MEM2_WB_Stall(MEM2_WB_Stall),

    .PREIF_IF_Flush(PREIF_IF_Flush),
    .IF_ID_Flush(IF_ID_Flush),
    .ID_EXE_Flush(ID_EXE_Flush),
    .EXE_MEM_Flush(EXE_MEM_Flush),
    .MEM_MEM2_Flush(MEM_MEM2_Flush),
    .MEM2_WB_Flush(MEM2_WB_Flush),
    .HiLo_Not_Flush(HiLo_Not_Flush)
);
assign Data_To_Reg = (WB_Data_To_Reg_Sel == 2'b00) ? WB_ALU_Out :       //??????????????????????
                     (WB_Data_To_Reg_Sel == 2'b01) ? WB_Data_From_DM : //load
                     (WB_Data_To_Reg_Sel == 2'b10) ? WB_PC + 8  :       //PC+8(dh??????????????PC+4,?????????PC+8)
                     (WB_Data_To_Reg_Sel == 2'b11) ? WB_CP0RdData:          
                     32'b0;
RF U_RF(
    .clk(aclk),
    .reset(aresetn),
    .WB_RFWr_End(WB_RFWr_End),
    .RA(ID_Instr[25:21]),
    .RB(ID_Instr[20:16]),
    .RW(WB_RW_End),
    .DataWr(Data_To_Reg),
    .DataOut1(ID_Rs_Data),
    .DataOut2(ID_Rt_Data)
);

CPU_IBus_Interface cpu_ibus();
CPU_DBus_Interface cpu_dbus();
AXI_IBus_Interface axi_ibus();
AXI_DBus_Interface axi_dbus();
AXI_UDCACHE_Interface axi_ubus();
AXI_UICACHE_Interface axi_ubus_fake();

logic[31:0]DataToDcache;

DcacheWen U_DcacheWen(
    .addr(MEM_DPhysicalAddr[11:0]),
    .DMOp(MEM_DMOp),
    .MEM_Data_Writed(MEM_Data_Writed),
    .MEM_DMWr(MEM_DMWr),
    .MEM_ExceptionType(MEM_ExceptionType),
    .DMRd(MEM_DMRd),
    .WB_ExceptionType(WB_ExceptionType),
    .DataToDcache(DataToDcache),
    .cache_wen(cpu_dbus.wstrb),
    .MEM_ExceptionTypeNew(MEM_ExceptionTypeNew)
);

MMU U_DMMU(
    .VirtualAddr(MEM_ALU_Out),
    .PhysicalAddr(MEM_DPhysicalAddr),
    .isCache(cpu_dbus.isCache)
);
Dcache U_Dcache(
    .clk(aclk),
    .resetn(aresetn),
    .cpu_bus(cpu_dbus.slave),    
    .axi_bus(axi_dbus.master),  
    .axi_ubus(axi_ubus.master)     
);
//没有加cache之前，只考虑到了异常时不能写的，因为就算读也没有损失，加上cache之后，异常之后就不要读了。
//如果有异常的话，就不用写读；如果在EXE级检测出来读写地址错误，也是不用读写的。
assign MEM_MemToRegWr_End=(IsExceptionorEret==`NoExceptionandEret)?MEM_MemToRegWr:0;
assign MEM_DMWr_End=(IsExceptionorEret==`NoExceptionandEret)?MEM_DMWr:0;



assign cpu_dbus.valid       = (MEM2_WB_Stall)?1'b0:(MEM_MemToRegWr_End||MEM_DMWr_End)?1:0;
assign cpu_dbus.op          = (MEM_MemToRegWr_End)?1'b0:
                              (MEM_DMWr_End)?1'b1:
                              1'b0;
assign cpu_dbus.tag         = MEM_DPhysicalAddr[31:12];
assign cpu_dbus.index       = MEM_DPhysicalAddr[11:4];
assign cpu_dbus.offset      = MEM_DPhysicalAddr[3:0];
assign cpu_dbus.wdata       = DataToDcache;
assign cpu_dbus.LoadType    = 3'b100;
assign cpu_dbus.stall       = MEM2_WB_Stall;

Icache U_Icache(
    .clk(aclk),
    .resetn(aresetn),
    .cpu_bus(cpu_ibus.slave),    
    .axi_bus(axi_ibus.master),   
    .axi_ubus(axi_ubus_fake.master)     
);

//MEM级判断出异常之后，IF_Npc就是异常入口，或者是EPC的值，这时候请求总是有效的
assign cpu_ibus.valid       = (IsExceptionorEret!=`NoExceptionandEret)?1'b1:
                            (ID_EXE_Flush_DH||PREIF_IF_Stall)?1'b0:
                            1'b1;
assign cpu_ibus.tag         = PREIF_PhyPC[31:12];
assign cpu_ibus.index       = PREIF_PhyPC[11:4];
assign cpu_ibus.offset      = PREIF_PhyPC[3:0];
assign cpu_ibus.stall       = PREIF_IF_Stall;


`ifdef USE_VERILATOR
AXI4Verilator
`else
AXI 
`endif U_AXI (
    .clk (aclk ),
    .rst (aresetn),
    .DCache_axi_interface (axi_dbus.slave ),
    .ICache_axi_interface (axi_ibus.slave ),
    .UICache_axi_interface(axi_ubus_fake.slave ),
    .UDCache_axi_interface(axi_ubus.slave ),
    .m_axi_arid (arid ),
    .m_axi_araddr (araddr ),
    .m_axi_arlen (arlen ),
    .m_axi_arsize (arsize ),
    .m_axi_arburst (arburst ),
    .m_axi_arlock (arlock ),
    .m_axi_arcache (arcache ),
    .m_axi_arprot (arprot ),
    .m_axi_arvalid (arvalid ),
    .m_axi_arready (arready ),
    .m_axi_rid (rid ),
    .m_axi_rdata (rdata ),
    .m_axi_rresp (rresp ),
    .m_axi_rlast (rlast ),
    .m_axi_rvalid (rvalid ),
    .m_axi_rready (rready ),
    .m_axi_awid (awid ),
    .m_axi_awaddr (awaddr ),
    .m_axi_awlen (awlen ),
    .m_axi_awsize (awsize ),
    .m_axi_awburst (awburst ),
    .m_axi_awlock (awlock ),
    .m_axi_awcache (awcache ),
    .m_axi_awprot (awprot ),
    .m_axi_awvalid (awvalid ),
    .m_axi_awready (awready ),
    .m_axi_wid (wid ),
    .m_axi_wdata (wdata ),
    .m_axi_wstrb (wstrb ),
    .m_axi_wlast (wlast ),
    .m_axi_wvalid (wvalid ),
    .m_axi_wready (wready ),
    .m_axi_bid (bid ),
    .m_axi_bresp (bresp ),
    .m_axi_bvalid (bvalid ),
    .m_axi_bready  (bready)
  );

          
assign CP0RdAddr=MEM2_Instr[15:11];
assign CP0WrAddr=MEM2_Instr[15:11];
assign MEM_CP0Wr_EXc=(WB_ExceptionType==`NoException)?1:0;

AsynExceptionType HardwareInterrupt;
CP0 U_CP0(
    .clk(aclk),
    .rst(aresetn),
    .CP0Wr(MEM2_CP0Wr),
    .CP0WrAddr(CP0WrAddr),
    .CP0WrData(MEM2_ALU_Out),
    .CP0RdAddr(CP0RdAddr),
    .WrongVirturalAddr(MEM2_ALU_Out),
    .CurrentInstrAddr(MEM2_PC),
    .ExceptionTypeEnd(MEM2_ExceptionType),
    .HardwareInterrupt(HardwareInterrupt),
    .IsDelayDlot(MEM2_isDelaySlot),
    .Is_Interrupt(Is_Interrupt),
    // output
    .CP0RdData(MEM2_CP0RdData),
    .CP0BadVAddr(CP0BadVAddr),
    .CP0Status(CP0Status),
    .CP0Cause(CP0Cause),
    .CP0EPC(CP0EPC),
    .CP0Count(CP0Count),
    .CP0Compare(CP0Compare),
    .Cp0TimerInterrupt(Cp0TimerInterrupt)
);

assign HardwareInterrupt = {ext_int[0],ext_int[1],ext_int[2],ext_int[3],ext_int[4],ext_int[5]};
Exception U_Exception(
    .clk(aclk),
    .rst(aresetn),

    .MEM2_Immjump(MEM2_Immjump),
    .MEM2_IsBranch(MEM2_IsBranch),
    .MEM_ExceptionTypeNew(MEM_ExceptionTypeNew),

    .CP0Status_in(CP0Status),
    .CP0EPC_in(CP0EPC),
    .CP0Cause_in(CP0Cause),

    .CP0Wr(MEM2_CP0Wr),
    .CP0WrAddr(CP0WrAddr),
    .CP0WrData(MEM2_ALU_Out),

    .EXE_Reg_Writed_Exception(EXE_Reg_Writed_Exception),

    .PREIF_IF_Flush_Exception(PREIF_IF_Flush_Exception),
    .IF_ID_Flush_Exception(IF_ID_Flush_Exception),
    .ID_EXE_Flush_Exception(ID_EXE_Flush_Exception),
    .EXE_MEM_Flush_Exception(EXE_MEM_Flush_Exception),

    .IsExceptionorEret(IsExceptionorEret),
    
    .MEM_ExceptionTypeEnd(MEM_ExceptionTypeEnd),
    .MEM_isDelaySlot(MEM_isDelaySlot),
    .CP0EPC_out(CP0EPC_out),
    .Is_Interrupt(Is_Interrupt)
);


endmodule